/**
 * JAVACC DEMO 1.0
 */
package com.apache.uct.common.filter;

import java.io.*;
import java.util.*;
import java.util.regex.Matcher;
import java.util.regex.Pattern;

import javax.servlet.*;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;

import com.alibaba.fastjson.JSON;
import com.apache.api.api.IBaseLoginUser;
import com.apache.api.vo.ResultMsg;
import com.apache.client.AesClientUtil;
import com.apache.license.validator.OsUtils;
import com.apache.oscache.OsCacheManager;
import com.apache.passport.common.PassportHelper;
import com.apache.tools.ConfigUtil;
import com.apache.tools.DateUtils;
import com.apache.tools.PropertiesConfig;
import com.apache.tools.StrUtil;
import org.apache.commons.lang.StringEscapeUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import com.apache.api.vo.ResultEntity;
import com.apache.cache.util.Validator;
import com.apache.license.filter.AbstractFilter;
import com.apache.license.validator.LicenseValidate;
import com.apache.rpc.common.JsonEntityParese;

import net.sf.json.JSONObject;

/**
 * description:  系统license验证类
 *
 * @author Hou Dayu 创建时间：2016-12-23
 */
public class LicenseFilter extends AbstractFilter {

	private Logger log = LoggerFactory.getLogger(getClass());
	private String loginUserService = "com.apache.client.common.DefLoginUserImpl";//获取loginUser接口实现类
	private String propertiesPath;
	private Properties prop;

	/**
	 * TODO 简单描述该方法的实现功能（可选）.
	 */
	public void destroy() {
		///
	}

	/**
	 * TODO 简单描述该方法的实现功能（可选）.
	 */
	public void init(FilterConfig arg0) throws ServletException {
		if(StrUtil.isNotNull(arg0.getInitParameter("loginUserService"))){
			loginUserService = arg0.getInitParameter("loginUserService");
		}
		this.initLincense();
		propertiesPath = Validator.getClassLoaderPath();
		prop = Validator.getProperties(propertiesPath,"cache-conf.properties");
		String authCode = prop.getProperty("cache_authorization_code");
		if(StrUtil.isNotNull(authCode)){
			JSONObject acjson = JSONObject.fromObject(AesClientUtil.getInstance().decryptEcbMode(authCode));
			if("0".equals(acjson.getString("infoType"))){
				prop.setProperty("cache_authorization_code","");
			}
		}
	}

	/**
	 * TODO 简单描述该方法的实现功能（可选）.
	 */
	public void doFilter(ServletRequest srequest, ServletResponse sresponse, FilterChain arg2)
			throws IOException, ServletException {
		HttpServletRequest request = (HttpServletRequest) srequest;
		HttpServletResponse response = (HttpServletResponse) sresponse;
		String path = request.getRequestURI();
		if (path.indexOf("/images/") !=-1 || path.indexOf("/js/") !=-1 || path.indexOf("/common/") !=-1 || path.indexOf("/template/") !=-1 ) {
			arg2.doFilter(request, response);
			return ;
		}

		String isOpenSecurity = StrUtil.doNull(ConfigUtil.getInstance().getValueByKey("is_open_security_filter"),"true");
		boolean mark = cleanXSS(request,isOpenSecurity);
		if (mark) {
			response.setStatus(500);
			this.outputJson(JSONObject.fromObject(new ResultMsg("F", "请求参数非法")).toString(), response, request.getParameter("callback"));
			return ;
		}
		boolean authFlag = AuthRequestSecurity();
		if(!authFlag){
			response.setStatus(500);
			this.outputJson(JSONObject.fromObject(new ResultMsg("F", "Invalid trial version authorization code")).toString(), response, request.getParameter("callback"));
			return ;
		}

		int s = path.indexOf("/doService");
		if (s >= 0) {
			if (!LicenseValidate.getInstance().isEffective()) {//license验证不通过
				ResultEntity entity = new ResultEntity();
				entity.setResult("false");
				entity.setMessage("功能已停用或已删除！");
				String callback = request.getParameter("callback");
				if (Validator.isNull(callback)) {
					response.setContentType("text/html; charset=UTF-8");
					PrintWriter out = response.getWriter();
					out.print(JsonEntityParese.instance().toXml(entity));
					out.flush();
				} else {///支持jsonp数据格式
					PrintWriter out = response.getWriter();
					response.setContentType("application/javascript");
					JSONObject json = JSONObject.fromObject(entity);
					out.print(callback + "(" + json.toString() + ")");
					out.flush();
				}
				return;
			}
		} else {
			String cookieValue = PassportHelper.getInstance().getTokenId(request);
			if(StrUtil.isNotNull(cookieValue)){
				Object loginUser = OsCacheManager.getInstance().getLoginUser(cookieValue);
				if(loginUser == null){
					try {
						Class<?> clazz = Class.forName(loginUserService);
						IBaseLoginUser loginService = (IBaseLoginUser) clazz.newInstance();
						loginUser = loginService.findLoginUser(cookieValue, request, response);
						request.getSession().setAttribute("loginUser", loginUser);//获取session中信息
					} catch (Exception e){
						log.error("按"+cookieValue+"获取loginUser信息失败");
					}
				}
			}
		}
		arg2.doFilter(request, response);
	}

	private boolean AuthRequestSecurity() {
		boolean checkFlag = true;
		String checkStr = getProperty("cache_authorization_code");
		String authorizationCode = PropertiesConfig.getApplicatinConfig("spring.authorization.code");
		long ntime = DateUtils.strToLong(DateUtils.Now.fmt_yyyyMMdd_HH(),DateUtils.FmtStr.yyyyMMdd_HH);
		JSONObject authJson = null;
		try {
			String ip = OsUtils.getLocalIp();
			if (StrUtil.isNull(checkStr) && StrUtil.isNull(authorizationCode)) {
				authJson = new JSONObject();
				authJson.put("infoType", "0");
				authJson.put("startTime", ntime);
				authJson.put("flag", "");
				String devStr = AesClientUtil.getInstance().encryptEcbMode(authJson.toString());
				setProperty(devStr);
			} else if (StrUtil.isNull(checkStr) && StrUtil.isNotNull(authorizationCode)) {
				boolean ifAuthFlag = isAuthCode(ntime, ip, authorizationCode);
				if (ifAuthFlag) {
					authJson = new JSONObject();
					authJson.put("infoType", "0");
					authJson.put("startTime", ntime);
					authJson.put("flag", "");
					String devStr = AesClientUtil.getInstance().encryptEcbMode(authJson.toString());
					setProperty(devStr);
				}
			} else {
				String strJson = AesClientUtil.getInstance().decryptEcbMode(checkStr);
				authJson = JSONObject.fromObject(strJson);
				String ipflag = authJson.getString("flag");
				boolean ifDev = "0".equals(authJson.getString("infoType"));
				if (ifDev || !ip.equals(ipflag)) {
					boolean testFlag = true;
					if (StrUtil.isNotNull(authorizationCode)) {
						testFlag = isAuthCode(ntime, ip, authorizationCode);
					}
					if (testFlag) {
						long ptime = authJson.getLong("startTime");
						if ((ntime - ptime) / 3600000 > 48 || !ifDev) {
							checkFlag = false;
						}
					}
				}
			}
		} catch (Exception e){
			checkFlag = false;
		}
		return checkFlag;
	}

	private boolean isAuthCode(long ntime, String ip, String authorizationCode){
		boolean testFlag = true;
		String acJsonStr = AesClientUtil.getInstance().decryptEcbMode(authorizationCode);
		JSONObject acjson = JSONObject.fromObject(acJsonStr);
		long stime = DateUtils.strToLong(acjson.getString("startTime"), DateUtils.FmtStr.yyyyMMdd_HH);
		int effectiveTime = acjson.getInt("effectiveTime");
		if((ntime-stime)/3600000 <= effectiveTime){
			acjson.put("infoType", "1");
			acjson.put("flag", ip);
			String devStr = AesClientUtil.getInstance().encryptEcbMode(acjson.toString());
			setProperty(devStr);
			testFlag = false;
		}
		return testFlag;
	}

	private String[] badStrs = { "<script", "confirm(", "prompt(", "eval(", "function(", "alert(", ":alert",
			"ltrim(", "[window[", "<iframe", "<a href", "<input ", "<img", "<audio", "onerror\\=", "ltrim(",
			"{tostring:", "</script", "</style", "href=","vbscript"};//过滤掉的sql关键字，可以手动添加

	private boolean cleanXSS(HttpServletRequest request, String isOpenSecurity) {
		if(!"true".equalsIgnoreCase(isOpenSecurity)){//没开启安全验证
			return false;
		}
		String pui = request.getRequestURI();
		if (pui.toLowerCase().contains("/owa_util.signature") || pui.toLowerCase().contains("/sqlnet.trc")) {
			return true;
		}
		if (StrUtil.isNotNull(request.getParameter("formToken"))) {
			return false;
		}
		Map<String, String[]> parameterMap = request.getParameterMap();
		StringBuilder sb = new StringBuilder();
		if(!parameterMap.isEmpty()) {
			Iterator it_d = parameterMap.entrySet().iterator();
			while (it_d.hasNext()) {
				Map.Entry<String, String[]> entry_d = (Map.Entry) it_d.next();
				String key = entry_d.getKey();
				String[] value = entry_d.getValue();
				if (value != null) {
					List<String> strings = Arrays.asList(value);
					for (int i = 0; i < strings.size(); i++) {
						String vstr = strings.get(i);
						strings.set(i, StringEscapeUtils.escapeHtml(vstr));
						strings.set(i, StringEscapeUtils.escapeJavaScript(vstr));
						if(vstr.length() < 200) {
							sb.append(strings.get(i));
						}
					}
				}
				parameterMap.put(key, value);
			}
			String newBody = JSON.toJSONString(parameterMap);
			if (newBody.contains("forbid")) {
				return true;
			}
		}
		sb.append(request.getQueryString());
		String referer = request.getHeader("Referer");
		sb.append(referer);
		String str = sb.toString();
		if (StrUtil.isNull(str))
			return false;
		String sql = str.toLowerCase();
		sql = sql.replace("%28", "(").replace("%2b", "+").replace("%3c", "<").replace("%27", "'").replace("%5b", "[")
				.replace("%5d", "]").replace("%3d", "=").replace("%7c", "|").replace("%7b", "{").replace("%3a", ":")
				.replace("%2f", "/");
		String security_filter_strs = ConfigUtil.getInstance().getValueByKey("security_filter_strs");
		if(StrUtil.isNotNull(security_filter_strs)){
			badStrs = security_filter_strs.split(",");
		}
		for (int i = 0; i < badStrs.length; i++) {
			if (sql.indexOf(badStrs[i]) >= 0) {
				return true;
			}
		}
		return isEqualString(str);
	}

	private boolean isEqualString(String str) {
		String regEx_style = "(<[a-zA-Z].*?>)|(<[\\/][a-zA-Z].*?>)";
		Pattern p = Pattern.compile(regEx_style);
		Matcher m = p.matcher(str);
		return m.matches();
	}

	/**
	 * 输出json数据
	 */
	private void outputJson(String json, HttpServletResponse response, String callback)
			throws IOException {
		if (StrUtil.isNotNull(json)) {
			PrintWriter out = response.getWriter();
			if (StrUtil.isNull(callback)) {
				response.setContentType("text/html;charset=UTF-8");
				response.setHeader("Access-Control-Allow-Origin", "*");
				response.setHeader("Access-Control-Allow-Methods", "POST,GET");
				response.setHeader("Access-Control-Allow-Credentials", "true");
				out.print(json);
			} else {
				response.setContentType("application/javascript");
				out.print(callback + "(" + json + ")");
			}
			out.flush();
			out.close();
		}
	}

	/**
	 * @Title: setProperty
	 * @Description: 保存key-value到配置文件中
	 */
	private void setProperty(String value) {
		try {
			if(prop != null) {
				prop.setProperty("cache_authorization_code", value);
				prop.store(new FileOutputStream(new File(propertiesPath+"cache-conf.properties")), "utf-8");
			}
		} catch(Exception ex) {
		}
	}

	private String getProperty(String key) {
		if(prop != null) {
			return prop.getProperty(key);
		}
		return "";
	}
}
